var defaultOpts = {
    data: null, //'数据'
    clickFirst: false,//创建完成后，点击第一个节点
    islistData: false,
    params: null, //远程加载时候附加的参数,可以定义再传其他字段作为参数['filed1','filed2']，默认不设置只传pid
    url: null, //请求数据的地址【如果有些请求参数是固定不变的，请去url中设置】
    textField: 'text', //菜单名称字段，默认为text
    idField: 'id', //菜单id字段,默认为id
    pidField: "pid",
    showLine: true, //显示连线
    getIdAndTxt: false, //获取勾选数据是否包括id及text
    showOptimize: 0, //当大数据量时候，采用的显示优化功能，配置0则不启用，否则每创建showOptimize条数据则执行显示
    checkSingle: false,//复选时候，不联动 父级、下级联动，默认值false    
    canClickParent: true, //点击事件时，是否可以点击父节点
    nodeParentIcon: 'k_tree_fold_closed',//父节点图标关闭状态
    nodeParentOpenIcon: 'k_tree_fold_open',      //打开状态图标
    leafNodeIcon: 'k_tree_file_icon',                //子节点图标 
    chkEmptyIcon: 'k_tree_check_empty',            //不选
    chkAllIcon: 'k_tree_check_all',            //全选
    chkSomeIcon: 'k_tree_check_some',              //部分选
    fontIconColor: undefined,//字体图标颜色定义
    checkedColor: undefined,//复选的图标颜色定义
    clickCheck: false, //是否点击复选       
    plainStyle: false, //true 为简单无图标样式
    tree2list: true,//回调api中的参数是否转为列表类型
    checkbox: false, //是否需要选择框
    disChecked: false, //是否禁用复选框 默认false
    clickItemCls: 'k_tree_clicked_cls', //点击行颜色  
    toolbarHide: undefined,//工具栏是否自动隐藏      
    toolbar: undefined, //是否需要工具栏,如果需要工具栏，则数据项中需要有toolbar工具栏组件的json
    toolAutoHide: true,
    onCreating: null,//创建每一项前回调,fn()
    onItemCreated: null, //项创建完成事件
    onClick: null, //function (data) { },//点击事件
    onLoaded: null, //加载完成事件function (data) { }
    onChecked: null, // function (data, params, checked) { } 选择事件,不建议注册onCheck事件，如果需要获取当前选择的数据，调用对象的getChecked即可
    onChange: null //function(name,newVal,oldVal)
};
//树转列表
function _tree2list(ins, resArr, beans) {
    if (!Array.isArray(beans)) {
        beans = [beans];
    }
    var nextChilds = [];
    for (let i = 0; i < beans.length; i++) {
        let bean = beans[i];
        if (bean.data) {
            resArr.push(bean.data);
        } else {
            resArr.push({ id: bean.id, text: bean.text });
        }
        if (bean.children) {
            Array.prototype.push.apply(nextChilds, bean.children);
        }
    }
    if (nextChilds.length > 0) {
        ins.optimizeTree2ListFn(ins, resArr, nextChilds);
    }
}

//列表转树形
function _list2tree(ins, res, list, pid) {
    let nextDataList = [];
    let idField = ins.opts.idField;
    let textField = ins.opts.textField;
    let pidField = ins.opts.pidField;
    for (let i = 0; i < list.length; i++) {
        let one = list[i];
        if (one[pidField] === pid) {
            res.push({
                id: one[idField],
                text: one[textField],
                data: one
            });
        } else {
            nextDataList.push(one);
        }
    }
    if (nextDataList.length > 0) {
        for (let i = 0; i < res.length; i++) {
            let one = res[i];
            let id = one[idField];
            let children = [];
            ins.optimize2treeFn(ins, children, nextDataList, id);
            if (children.length > 0) {
                one["children"] = children;
            }
        }
    }
}
function _createTreeItem(ins, ul, param, list) {
    ins.itemCounting++;
    let deep = param.deep;
    let endCount = param.endCount;
    let fragment = document.createDocumentFragment();
    if (!ins.liEl) {
        let liHtml = "<li><div event='itemEvent' style='display:inline-block;min-width:100%;white-space:nowrap;' class='k_tree_item_wrap k_box_size'><div class='k_tree_text k_box_size'></div></div></li>";
        ins.liEl = $B.DomUtils.createEl(liHtml);
    }
    if (!ins.deepEl) {
        let deepHtml = '<div class="k_tree_deep_size"></div>';
        ins.deepEl = $B.DomUtils.createEl(deepHtml);
    }
    if (!ins.childUl) {
        ins.childUl = $B.DomUtils.createEl("<ul class='k_tree_ul'>");
    }
    let nextDeep = deep + 1;
    let hasParent = false;
    let lastChild, imgCssName = "k_tree_icon_img";
    let lastIdx = list.length - 1;
    let isToolbar = Array.isArray(ins.opts.toolbar);
    let toolbarBtn, toolbarWrap;
    if (isToolbar) {
        toolbarBtn = $B.DomUtils.createEl("<div class='k_tree_button'><i class='fa'></i><span></span></div>");
        toolbarWrap = $B.DomUtils.createEl("<div class='k_tree_button_wrap'></div>");
    }
    for (let i = 0; i < list.length; i++) {
        let iconNode, checkNode, data, id, text, $li, $wrap, $txt, _deep = deep, clz, nextEndCount;
        let tmpEndCount = endCount;
        data = list[i];
        let isParent = $B.isArrayFn(data.children);
        let isChildEmpty = isParent && data.children.length === 0 ? true : false;
        id = data.id;
        text = data.text;
        if(!id){
            id = data.data[ins.opts.idField];
        }
        if(!text){
            text = data.data[ins.opts.textField];
        }
        if (isChildEmpty) {
            data.closed = true;
        }else if(typeof data.closed === "undefined"){
            if(this.openDeep && this.openDeep !== _deep){
                data.closed = true;
            }
        }  
        $li = ins.liEl.cloneNode(true);
        $wrap = $B.DomUtils.children($li, ins._divName);
        if (ins.opts.onCreating) {
            ins.opts.onCreating.call($wrap, data, isParent);
        }
        $B.DomUtils.setData($wrap, ins.dataBeanKey, data);
        $B.DomUtils.attribute($wrap, { deep: deep });
        $B.DomUtils.attribute($li, { id: "_" + id });
        ins.bindEvents($wrap);
        $txt = $B.DomUtils.findByClass($li, ins._textClz)[0];
        $B.DomUtils.text($txt, text);
        while (_deep > 0) {
            let $deepEl = ins.deepEl.cloneNode(true);
            $B.DomUtils.before($txt, $deepEl);
            _deep--;
        }
        if (!ins.opts.plainStyle) { //加入父节点文件夹图标
            iconNode = ins.deepEl.cloneNode(true);
            $B.DomUtils.attribute(iconNode, { event: 'parentEvent' });
            if (isParent) {
                if (data.closed) {
                    clz = ins.opts.nodeParentIcon + " _parent_";
                } else {
                    clz = ins.opts.nodeParentOpenIcon + " _parent_";
                }
                if (ins.isFontIcon) {
                    $B.DomUtils.addClass(iconNode, "k_tree_font_icon _parent_");
                    let $i = $B.DomUtils.append(iconNode, "<i event='parentEvent' class='fa " + clz + "'></i>");
                    if (ins.opts.fontIconColor) {
                        $B.DomUtils.css($i, { color: ins.opts.fontIconColor });
                    }
                } else {
                    $B.DomUtils.addClass(iconNode, imgCssName + " " + clz);
                }
            } else {
                if (ins.isFontIcon) {
                    $B.DomUtils.addClass(iconNode, "k_tree_font_icon");
                    let $i = $B.DomUtils.append(iconNode, "<i class='fa " + ins.opts.leafNodeIcon + "'></i>");
                    if (ins.opts.fontIconColor) {
                        $B.DomUtils.css($i, { color: ins.opts.fontIconColor });
                    }
                } else {
                    $B.DomUtils.addClass(iconNode, imgCssName + " " + ins.opts.leafNodeIcon);
                }
            }
            $B.DomUtils.before($txt, iconNode);
        }
        if (ins.opts.checkbox) {
            checkNode = ins.deepEl.cloneNode(true);
            if (ins.opts.disChecked) {
                $B.DomUtils.addClass(checkNode, "k_tree_check_disabled");
            }
            $B.DomUtils.before($txt, checkNode);
            $B.DomUtils.attribute(checkNode, { event: 'checkEvent' });
            $B.DomUtils.addClass(checkNode, "k_tree_check_box");
            let defChkIcon = ins.opts.chkEmptyIcon;
            if (data.checked) {
                defChkIcon = ins.opts.chkAllIcon;
            }
            if (ins.isFontIcon) {
                let fontNode = $B.DomUtils.append(checkNode, "<i event='checkEvent' class='fa'></i>");
                $B.DomUtils.addClass(fontNode, defChkIcon);
                if (ins.opts.fontIconColor) {
                    $B.DomUtils.css(fontNode, { color: ins.opts.fontIconColor });
                }
                if (data.checked && ins.opts.checkedColor) {
                    $B.DomUtils.css(fontNode, { color: ins.opts.checkedColor });
                }
            } else {
                $B.DomUtils.addClass(checkNode, imgCssName + " " + defChkIcon);
            }
        }
        //补充线样式
        if (ins.opts.plainStyle || ins.opts.showLine) {
            _deep = deep;
            let isFirst = i === 0;
            let isLast = i === lastIdx;
            let startNode = $txt;
            if (checkNode) {
                startNode = checkNode;
            }
            if (iconNode) {
                startNode = iconNode;
            }
            startNode = startNode.previousSibling;
            let fixListCls = 'k_tree_line_last';
            if (isParent) { //如果是父节点
                if (isFirst && isLast) {
                    if (data.closed) {
                        $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_last_closed _node_");
                    } else {
                        $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_open _node_");
                    }
                } else if (isFirst) {
                    if (data.closed) {
                        $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_closed _node_");
                    } else {
                        $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_open _node_");
                    }
                } else if (isLast) {
                    if (data.closed) {
                        $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_last_closed _node_");
                    } else {
                        $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_open _node_");
                    }
                } else {
                    if (data.closed) {
                        $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_closed _node_");
                    } else {
                        $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_open _node_");
                    }
                }
                $B.DomUtils.attribute(startNode, { "event": "parentEvent" });
                let attr = { endCount: endCount }
                if (isLast) {
                    attr["islast"] = true;
                    if (!isChildEmpty && !data.closed) {
                        tmpEndCount = 0;
                        fixListCls = 'k_tree_line_vertical';
                    }
                } else {
                    tmpEndCount = 0;
                    fixListCls = 'k_tree_line_vertical';
                }
                $B.DomUtils.attribute($wrap, attr);
            } else {//如果是子节点
                if (isLast) {
                    $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_last");                  
                } else {
                    fixListCls = "k_tree_line_vertical";
                    $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_cross");
                    tmpEndCount--;
                }
            }
            while (tmpEndCount > 0 && startNode) {
                startNode = startNode.previousSibling;
                if (startNode) {
                    $B.DomUtils.addClass(startNode, imgCssName + " " + fixListCls);
                }
                tmpEndCount--;
            }
            if (startNode) {
                startNode = startNode.previousSibling;
                while (startNode) {
                    $B.DomUtils.addClass(startNode, imgCssName + " k_tree_line_vertical");
                    startNode = startNode.previousSibling;
                }
            }
        }
        fragment.appendChild($li);
        if (isParent) {
            nextEndCount = endCount;
            let isEndNode = i === list.length - 1;
            if (isEndNode) {
                nextEndCount++;               
            } else { //末节点关系被打断
                nextEndCount = 0;
            }
            hasParent = true;
            let ul = ins.childUl.cloneNode(true);
            if (data.closed) {
                ul.style.display = "none";
            }
            $B.DomUtils.append($li, ul);
            if (data.children.length > 0) {
                let loopPrs = { deep: nextDeep, endCount: nextEndCount };
                if (isEndNode) {
                    loopPrs.parentEnd = true;
                }
                if (ins.opts.showOptimize && ins.itemCounting > ins.opts.showOptimize) {
                    if (!ins.taskStack) {
                        ins.taskStack = [];
                    }
                    let stackKey = setTimeout(() => {
                        ins.optimizeCreateFn(ins, ul, loopPrs, data.children);
                        ins.taskStack.pop();
                    }, 1);
                    ins.taskStack.push(stackKey);
                } else {
                    ins.optimizeCreateFn(ins, ul, loopPrs, data.children);
                }
            }
        } else {//记录最末端节点
            if (!lastChild && $li) {
                lastChild = $li;
            }
        }
        let tools;
        if (isToolbar) {
            tools = ins.opts.toolbar.length;
        }
        if (data.toolbar) {
            if (!toolbarBtn) {
                toolbarBtn = $B.DomUtils.createEl("<div class='k_tree_button'><i class='fa'></i><span></span></div>");
                toolbarWrap = $B.DomUtils.createEl("<div class='k_tree_button_wrap'></div>");
                ins.opts.toolbar = true;
            }
            tools = data.toolbar;
        }
        if (tools) {
            let toolWrap = toolbarWrap.cloneNode(true);
            $B.DomUtils.after($txt, toolWrap);
            let evAtrr = { "event": "toolEvent" };
            if (ins.opts.toolbarHide) {
                $B.DomUtils.css(toolWrap, { display: "none" });
            }
            for (let k = 0; k < tools.length; k++) {
                let toolBtn = tools[k];
                let btn = toolbarBtn.cloneNode(true);
                $B.DomUtils.attribute(btn, evAtrr);
                let ibtn = $B.DomUtils.children(btn, "i");
                $B.DomUtils.attribute(ibtn, evAtrr);
                if (toolBtn.iconCls) {
                    $B.DomUtils.addClass(ibtn, toolBtn.iconCls);
                    if (toolBtn.color) {
                        $B.DomUtils.css(ibtn, { color: toolBtn.color });
                    }
                } else {
                    $B.DomUtils.remove(ibtn);
                }
                let itxt = $B.DomUtils.children(btn, "span");
                $B.DomUtils.attribute(itxt, evAtrr);
                if (toolBtn.showText) {
                    $B.DomUtils.text(itxt, toolBtn.text);
                } else {
                    $B.DomUtils.attribute(ibtn, { title: toolBtn.text });
                }
                $B.DomUtils.append(toolWrap, btn);
                ins.toolbarEventIndex++;
                $B.DomUtils.attribute(btn, { eventidx: ins.toolbarEventIndex });
                if (typeof toolBtn.click === "function") {
                    ins.toolbarEvents[ins.toolbarEventIndex] = toolBtn.click;
                } else {
                    let methodsObject = toolBtn.methodsObject ? toolBtn.methodsObject : ins.opts.methodsObject;
                    if (methodsObject && window[methodsObject]) {
                        ins.toolbarEvents[ins.toolbarEventIndex] = window[methodsObject][toolBtn.click];
                    } else {
                        ins.toolbarEvents[ins.toolbarEventIndex] = undefined;
                    }
                }
            }
        }
        if (ins.opts.onItemCreated) {
            ins.opts.onItemCreated.call(ins, $li, data);
        }
        if (ins.opts.clickFirst && !ins.$firstEL) {
            ins.$firstEL = $li;
        }
    }
    if (fragment.childNodes.length > 0) {
        ul.appendChild(fragment);
    }
    if (ins.opts.checkbox && !hasParent && lastChild) {
        ins.leafNodeArray.push(lastChild);//用于递归渲染父节点的勾选情况
    }
}
function _load(ins, ul, param, clickNodeBtnEl, callBack) {
    let url = ins.opts.url;
    let pel = $B.DomUtils.previous(ul);
    let method = (url.indexOf(".data") > 0 || url.indexOf(".json") > 0) ? "GET" : "POST";
    var loading = $B.getIconLoading("k_tree_deep_size k_simple_loading");
    if (pel && $B.DomUtils.hasClass(pel, "k_tree_item_wrap")) {
        let all = $B.DomUtils.children(clickNodeBtnEl);
        if (all.length > 0) {
            $B.DomUtils.hide(all);
        }
        $B.DomUtils.append(clickNodeBtnEl, loading);
    } else {
        let li = $B.DomUtils.createEl("<li/>");
        $B.DomUtils.append(li, loading);
        $B.DomUtils.css(loading, { "padding-left": "6px" });
        $B.DomUtils.append(ul, li);
        loading = li;
    }
    $B.request({
        dataType: 'json',
        url: url,
        data: param,
        type: method,
        onErrorEval: true,
        onReturn: function () {
            try {
                $B.removeLoading(loading, () => {
                    loading = undefined;
                });
                if (clickNodeBtnEl) {
                    let all = $B.DomUtils.children(clickNodeBtnEl);
                    if (all.length > 0) {
                        $B.DomUtils.show(all);
                    }
                    setTimeout(() => {
                        clickNodeBtnEl = undefined;
                    }, 10);
                }
            } catch (ex) {
                console.log(ex);
            }
        },
        ok: function (message, data) {
            if(ins.opts.onLoaded){
                setTimeout(()=>{
                    ins.opts.onLoaded(data);
                },10);
            }
            if (!data || data.length === 0) {
                if (clickNodeBtnEl) {
                    $B.toolTip(clickNodeBtnEl, ($B.config && $B.config.returnEmptyData) ? $B.config.returnEmptyData : 'the return is empty!', 2);
                } else {
                    $B.toolTip(ul, ($B.config && $B.config.returnEmptyData) ? $B.config.returnEmptyData : 'the return is empty!', 2);
                }
                return;
            }
            ins.itemCounting = 0;
            ins.leafNodeArray = [];
            var treeData = data;
            if (ins.opts.islistData) {
                treeData = ins._formatData(data);
            } else {
                if (!$B.isArrayFn(data)) {
                    treeData = [data];
                }
            }
            let deep = 1, endCount = 0;
            let isLast;
            if (pel && $B.DomUtils.hasClass(pel, "k_tree_item_wrap")) {
                deep = parseInt($B.DomUtils.attribute(pel, "deep")) + 1;
                endCount = parseInt($B.DomUtils.attribute(pel, "endCount"));
                isLast = $B.DomUtils.attr(pel, "islast");
                if (isLast) {
                    endCount++;
                } else {
                    endCount = 0;
                }
            }
            let loopPrs = { deep: deep, endCount: endCount };
            if (isLast) {
                loopPrs.parentEnd = true;
            }
            ins.optimizeCreateFn(ins, ul, loopPrs, treeData);
            callBack(treeData);
        }
    });
}
function _loopChilds(ins, params, ul) {
    if (ul) {
        let lis = $B.DomUtils.children(ul, "li");
        for (let i = 0; i < lis.length; i++) {
            let li = lis[i];
            let childs = $B.DomUtils.children(li);
            let $w = childs[0];
            let data = $B.DomUtils.getData($w, ins.dataBeanKey);
            data.checked = params.checked;
            let icon = $B.DomUtils.children($w, ".k_tree_check_box");
            if (ins.isFontIcon) {
                icon = $B.DomUtils.children(icon, "i");
            }
            if (params.checked) {
                $B.DomUtils.removeClass(icon, ins.opts.chkEmptyIcon + " " + ins.opts.chkSomeIcon);
                $B.DomUtils.addClass(icon, ins.opts.chkAllIcon);
                ins._modifyChkIconColor(1, icon);
            } else {
                $B.DomUtils.removeClass(icon, ins.opts.chkAllIcon + " " + ins.opts.chkSomeIcon);
                $B.DomUtils.addClass(icon, ins.opts.chkEmptyIcon);
                ins._modifyChkIconColor(-1, icon);
            }
            if (childs.length === 2) {
                ins.optimizeLoopChildsFn(ins, params, childs[1]);
            }
        }
    }
}
function _loopParents(ins, params, li) {
    var ul = li.parentNode;
    var parentWrap = $B.DomUtils.previous(ul);
    if (parentWrap && $B.DomUtils.hasClass(parentWrap, "k_tree_item_wrap")) {
        let checkStatu = params.checkStatu;
        let chkIcon = $B.DomUtils.children(parentWrap, ".k_tree_check_box");
        if (ins.isFontIcon) {
            chkIcon = $B.DomUtils.children(chkIcon, "i");
        }
        let data = $B.DomUtils.getData(parentWrap, ins.dataBeanKey);
        if (checkStatu === -1) {
            $B.DomUtils.removeClass(chkIcon, ins.opts.chkAllIcon + " " + ins.opts.chkSomeIcon);
            $B.DomUtils.addClass(chkIcon, ins.opts.chkEmptyIcon);
            data.checked = false;
            ins._modifyChkIconColor(-1, chkIcon);
        } else if (checkStatu === 1) {
            data.checked = true;
            $B.DomUtils.removeClass(chkIcon, ins.opts.chkEmptyIcon + " " + ins.opts.chkSomeIcon);
            $B.DomUtils.addClass(chkIcon, ins.opts.chkAllIcon);
            ins._modifyChkIconColor(1, chkIcon);
        } else {
            data.checked = false;
            $B.DomUtils.removeClass(chkIcon, ins.opts.chkAllIcon + " " + ins.opts.chkEmptyIcon);
            $B.DomUtils.addClass(chkIcon, ins.opts.chkSomeIcon);
            ins._modifyChkIconColor(0, chkIcon);
        }
        var deep = $B.DomUtils.attribute(parentWrap, "deep");
        if (deep !== "1") { //向上递归
            let liList = $B.DomUtils.children(parentWrap.parentNode.parentNode);
            let res = _getSiblingsFlag(ins, liList, ins.isFontIcon);
            checkStatu = 0;
            if (res.isCheckAll) {
                checkStatu = 1;
            } else if (res.isUnCheckAll) {
                checkStatu = -1;
            }
            ins.optimizeLoopParentsFn(ins, { checkStatu: checkStatu }, parentWrap.parentNode);
        }
    }
}
function _loopFN(ins, ul, onLoopFN) {
    let childs = ul.children;
    for (let i = 0; i < childs.length; i++) {
        let li = childs[i];
        let ret = onLoopFN(li);
        if (ret) {
            return;
        }
        if (li.firstChild.nextSibling) {
            ins.optimizeLoopTreeFn(ins, li.firstChild.nextSibling, onLoopFN);
        }
    }
}

/**获取同级元素的复选情况***/
function _getSiblingsFlag(ins, sblings, isFontIcon) {
    var checked = 0,
        unchecked = 0,
        other = 0;
    for (let i = 0; i < sblings.length; i++) {
        li = sblings[i];
        let $w = $B.DomUtils.children(li, "div");
        let chkIcon = $B.DomUtils.children($w, ".k_tree_check_box");
        if (isFontIcon) {
            chkIcon = $B.DomUtils.children(chkIcon, "i");
        }
        if ($B.DomUtils.hasClass(chkIcon, ins.opts.chkEmptyIcon)) {
            unchecked++;
        } else if ($B.DomUtils.hasClass(chkIcon, ins.opts.chkAllIcon)) {
            checked++;
        } else {
            other++;
        }
        if ((unchecked > 0 && checked > 0) || (unchecked > 0 && other > 0) || (checked > 0 && other > 0)) {
            break;
        }
    }
    return {
        isCheckAll: sblings.length === checked,
        isUnCheckAll: sblings.length === unchecked
    };
}
class Tree extends $B.BaseControl {
    constructor(elObj, opts) {
        super();
        var _this = this;
        super.setElObj(elObj);
        this._textClz = ".k_tree_text";
        this._divName = "div";
        this.dataBeanKey = "bean";
        this.itemCounting = 0;
        this.leafNodeArray = [];
        this.toolbarEventIndex = 1;
        this.toolbarEvents = {};
        this.optimize2treeFn = $B.recursionFn(_list2tree, true);
        this.optimizeCreateFn = $B.recursionFn(_createTreeItem, true);
        this.optimizeLoopChildsFn = $B.recursionFn(_loopChilds, true);
        this.optimizeLoopParentsFn = $B.recursionFn(_loopParents, true);
        this.optimizeLoopTreeFn = $B.recursionFn(_loopFN, true);
        this.optimizeTree2ListFn = $B.recursionFn(_tree2list, true);
        $B.DomUtils.addClass(this.elObj, "k_tree_ul k_tree_root k_box_size");
        this.opts = $B.extendObjectFn(true, {}, defaultOpts, opts);
        this.isFontIcon = this.opts.nodeParentIcon.indexOf("fa-") === 0;
        if (!this.opts.showLine) {
            this.opts.plainStyle = false;
        }
        this.clickedItem = undefined;
        if (this.opts.data) {
            if (this.opts.islistData) {
                this.opts.data = this._formatData(this.opts.data);
            } else {
                if (!$B.isArrayFn(this.opts.data)) {
                    this.opts.data = [this.opts.data];
                }
            }
            this.optimizeCreateFn(this, this.elObj, { deep: 1, endCount: 0 }, this.opts.data);
            this.triggerFirstClick();
        } else if (this.opts.url && this.opts.url !== "") {
            _load(this, _this.elObj, { pid: "" }, undefined, (data) => {
                this.opts.data = data;
                this.triggerFirstClick();
            });
        }
        this.liEl = undefined;
        this.deepEl = undefined;
        this.childUl = undefined;
        if (this.opts.showOptimize) {
            this._checkCreated = setInterval(() => {
                if (!this.taskStack.length) {
                    this._loopCheckedUiRender();
                    clearInterval(this._checkCreated);
                    if (this.opts.onCreated) {
                        this.opts.onCreated();
                    }
                }
            }, 50);
        } else {
            this._loopCheckedUiRender();
        }
    }
    _loopCheckedUiRender() {
        for (let i = 0; i < this.leafNodeArray.length; i++) {
            this._loopCrcParentCheck(this.leafNodeArray[i]);
        }
        this.leafNodeArray = [];
    }
    _formatData(list, pid) {
        if (!pid) {
            pid = "";
        }
        var res = [];
        this.optimize2treeFn(this, res, list, pid);
        return res;
    }
    bindEvents(node) {
        if (!this.itemEventHandler) {
            var _this = this;
            this.itemEventHandler = function (e) {
                let event = $B.DomUtils.attribute(e.target, "event");
                if (!event) {
                    event = "itemEvent";
                }
                if (_this[event]) {
                    _this[event](e);
                }
                return false;
            };
            //mosueover ，mouseout事件
            if (this.opts.toolAutoHide && this.opts.toolbar) {
                this.mouseEvents = {
                    mouseenter: (e) => {
                        let res = this.getClickItemData(e.target, true);
                        let el = res.el;
                        let tool = $B.DomUtils.children(el, ".k_tree_button_wrap");
                        $B.DomUtils.show(tool);
                    },
                    mouseleave: (e) => {
                        let res = this.getClickItemData(e.target, true);
                        let el = res.el;
                        let tool = $B.DomUtils.children(el, ".k_tree_button_wrap");
                        $B.DomUtils.hide(tool);
                    }
                };
            }
        }
        $B.DomUtils.click(node, this.itemEventHandler);
        if (this.opts.toolAutoHide && this.opts.toolbar) {
            $B.DomUtils.bind(node, this.mouseEvents);
        }
    }
    getClickItemData(el, notData) {
        var res;
        while (el) {
            if ($B.DomUtils.hasClass(el, "k_tree_item_wrap")) {
                let _data;
                if (!notData) {
                    _data = $B.DomUtils.getData(el, this.dataBeanKey);
                }
                res = {
                    el: el,
                    bean: _data,
                    data: _data
                };
                break;
            }
            el = el.parentNode;
        }
        if (!notData && this.opts.tree2list) { //将data树转换数组
            let arr = [];
            this.optimizeTree2ListFn(this, arr, res.data);
            res.data = arr;
        }
        return res;
    }
    itemEvent(e) {
        var res = this.getClickItemData(e.target);
        var el = res.el;
        if (!this.opts.canClickParent) {
            let ul = $B.DomUtils.next(el);
            if (ul) {
                return;
            }
        }
        if (this.opts.clickItemCls) {
            if (this.clickedItem) {
                $B.DomUtils.removeClass(this.clickedItem, this.opts.clickItemCls);
            }
            this.clickedItem = $B.DomUtils.addClass(el, this.opts.clickItemCls);
        }
        if (this.opts.onClick && !e._istrigger) {
            e.data = res.data;
            setTimeout(() => {
                this.opts.onClick.call(res.el, e);
            }, 1);
        }
        if (this.opts.clickCheck && this.opts.checkbox && !e._istrigger) {
            var box = $B.DomUtils.children(el, ".k_tree_check_box")[0];
            this.checkEvent({ target: box });
        }
    }
    toolEvent(e) {
        var res = this.getClickItemData(e.target);
        var eventIdx = $B.DomUtils.attribute(e.target.parentNode, "eventidx");
        e.data = res.data;
        var fn = this.toolbarEvents[eventIdx];
        if (typeof fn === "function") {
            fn.call(e.target.parentNode, e);
        } else {
            console.log("not found function,", fn);
        }
    }
    parentEvent(e) {        
        let res = this.getClickItemData(e.target);
        let el = res.el;
        let ul = el.nextSibling;
        let duration = 200;
        let _this = this;
        let oprIcon = e.target;
        let nodeBtn;
        if ($B.DomUtils.hasClass(oprIcon, "_node_")) {
            nodeBtn = oprIcon;
            oprIcon = oprIcon.nextSibling;
            if (oprIcon) {
                if (!$B.DomUtils.hasClass(oprIcon, "_parent_")) {
                    oprIcon = undefined;
                }
            }
        } else {
            nodeBtn = e.target.previousSibling;
            if (e.target.tagName === "I") {
                nodeBtn = e.target.parentNode.previousSibling;
            }
        }
        if (nodeBtn && !$B.DomUtils.hasClass(nodeBtn, "_node_")) {
            nodeBtn = undefined;
        }
        if (this.isFontIcon && oprIcon && oprIcon.tagName === "DIV") {
            oprIcon = $B.DomUtils.children(oprIcon, "i")[0];
        }
        if (ul) {
            let isLast = $B.DomUtils.attribute(el, "islast");
            let endcount = parseInt($B.DomUtils.attribute(el, "endcount"));
            if (oprIcon) {
                if (oprIcon.tagName === "I") {
                    lineNode = oprIcon.parentNode.previousSibling;
                } else {
                    lineNode = oprIcon.previousSibling;
                }
            }
            var isOpening, lineNode;
            var nodeAnimateFn = () => {
                if (isOpening) { //展开
                    if (oprIcon) {
                        $B.DomUtils.removeClass(oprIcon, _this.opts.nodeParentIcon);
                        $B.DomUtils.addClass(oprIcon, _this.opts.nodeParentOpenIcon);
                    }
                    if (isLast) {//最后一个
                        if (nodeBtn) {
                            $B.DomUtils.removeClass(nodeBtn, "k_tree_line_last_closed");
                            $B.DomUtils.addClass(nodeBtn, "k_tree_line_open");
                        }
                    } else {
                        $B.DomUtils.removeClass(nodeBtn, "k_tree_line_closed");
                        $B.DomUtils.addClass(nodeBtn, "k_tree_line_open");
                    }                    
                    if (this.opts.url && $B.DomUtils.children(ul).length === 0) {
                        let id;
                        if (this.opts.tree2list) {
                            id = res.data[0][this.opts.idField];
                        } else {
                            id = res.data.data[this.opts.idField];
                        }
                        let clickBtn = e.target;
                        if (e.target.tagName === "I") {
                            clickBtn = e.target.parentNode;
                        }
                        let deep = $B.Dom.attr(el,"deep");   
                        this.openDeep = deep + 1;                 
                        _load(this, ul, { pid: id  }, clickBtn, (retData) => {
                            res.bean.children = retData;
                            this.openDeep = undefined;
                        });
                    }
                } else {//收起
                    if (oprIcon) {
                        $B.DomUtils.removeClass(oprIcon, _this.opts.nodeParentOpenIcon);
                        $B.DomUtils.addClass(oprIcon, _this.opts.nodeParentIcon);
                    }
                    if (isLast) {//最后一个
                        if (nodeBtn) {
                            $B.DomUtils.removeClass(nodeBtn, "k_tree_line_open");
                            $B.DomUtils.addClass(nodeBtn, "k_tree_line_last_closed");
                            lineNode = nodeBtn.previousSibling;
                            while (endcount > 0) {
                                $B.DomUtils.removeClass(lineNode, "k_tree_line_vertical");
                                $B.DomUtils.addClass(lineNode, "k_tree_line_last");
                                lineNode = lineNode.previousSibling;
                                endcount--;
                            }
                        }
                    } else {
                        if (nodeBtn) {
                            $B.DomUtils.removeClass(nodeBtn, "k_tree_line_open");
                            $B.DomUtils.addClass(nodeBtn, "k_tree_line_closed");
                        }
                    }
                }
            };
            if ($B.DomUtils.css(ul, "display") === "none") {
                isOpening = true;
                $B.slideDown(ul, duration, nodeAnimateFn);
                if (nodeBtn) {
                    lineNode = nodeBtn.previousSibling;
                    while (endcount > 0) {
                        $B.DomUtils.removeClass(lineNode, "k_tree_line_last");
                        $B.DomUtils.addClass(lineNode, "k_tree_line_vertical");
                        lineNode = lineNode.previousSibling;
                        endcount--;
                    }
                }
            } else {
                $B.slideUp(ul, duration, nodeAnimateFn);
            }
        }
    }
    checkEvent(e) {
        if (this.opts.disChecked) {
            return;
        }
        var res = this.getClickItemData(e.target);
        var el = res.el;
        var data = res.data;
        if (!this.opts.canClickParent) {
            let ul = $B.DomUtils.next(el);
            if (ul) {
                return;
            }
        }
        let oldData;
        if (this.opts.onChange && !e._istrigger) {
            oldData = this.getCheckData();
        }
        var iconEl = e.target;
        if (this.isFontIcon && iconEl.tagName === "DIV") {
            iconEl = $B.DomUtils.children(iconEl, "i");
        }
        var ischecked = !$B.DomUtils.hasClass(iconEl, this.opts.chkAllIcon);
        data.checked = ischecked;
        if (ischecked) { //变全选
            $B.DomUtils.removeClass(iconEl, this.opts.chkEmptyIcon + " " + this.opts.chkSomeIcon);
            $B.DomUtils.addClass(iconEl, this.opts.chkAllIcon);
            this._modifyChkIconColor(1, iconEl);
        } else {//变不选
            $B.DomUtils.removeClass(iconEl, this.opts.chkAllIcon + " " + this.opts.chkSomeIcon);
            $B.DomUtils.addClass(iconEl, this.opts.chkEmptyIcon);
            this._modifyChkIconColor(-1, iconEl);
        }
        if (!this.opts.checkSingle) {
            this.optimizeLoopChildsFn(this, { checked: ischecked }, el.nextSibling);
            this._loopCrcParentCheck(el.parentNode);
        }
        if (this.opts.onChecked && !e._istrigger) {
            setTimeout(() => {
                this.opts.onChecked.call(el, data, ischecked);
            }, 1);
        }
        if (this.opts.onChange && !e._istrigger) {
            setTimeout(() => {
                let newData = this.getCheckData();
                this.opts.onChange(this.id, newData, oldData);
            }, 1);
        }
    }
    /**
     * -1 不选择，0部分选择，1全选
     * **/
    _modifyChkIconColor(flag, iconEl) {
        if (this.isFontIcon && this.opts.checkedColor) {
            if (flag === -1) {//不选择
                if (this.opts.fontIconColor) {
                    $B.DomUtils.css(iconEl, { color: this.opts.fontIconColor });
                } else {
                    let styleObj = $B.style2cssObj(iconEl);
                    delete styleObj["color"];
                    $B.DomUtils.attribute(iconEl, { style: $B.cssObj2string(styleObj) });
                }
            } else {
                $B.DomUtils.css(iconEl, { color: this.opts.checkedColor });
            }
        }
    }
    _loopCrcParentCheck(li) {
        //当前节点是否全选，来更新父节点上的勾选ui：1全选，0部分选，-1都不选
        var lisList = $B.DomUtils.children(li.parentNode);
        var res = _getSiblingsFlag(this, lisList, this.isFontIcon);
        var flag = 0;
        if (res.isCheckAll) {
            flag = 1;
        } else if (res.isUnCheckAll) {
            flag = -1;
        }
        var parentParam = { checkStatu: flag };
        this.optimizeLoopParentsFn(this, parentParam, li);
    }
    getCheckData(onlyId) {
        if (typeof onlyId === "undefined") {
            onlyId = !this.opts.getIdAndTxt;
        }
        var getNotEmpty = false;
        if (arguments.length === 2) {
            getNotEmpty = arguments[1];
        }
        let ret = [];
        if (!this.opts.checkbox) {
            if (this.clickedItem) {
                let id = $B.DomUtils.attribute(this.clickedItem.parentNode, "id").replace("_","");
                if (typeof onlyId === "undefined" || onlyId) {
                    ret.push(id);
                } else {
                    let $txt = $B.DomUtils.children(this.clickedItem, ".k_tree_text")[0];
                    ret.push({ id: id, text: $txt.innerText });
                }
            }
            return ret;
        }
        this.optimizeLoopTreeFn(this, this.elObj, (li) => {
            let $wap = li.firstChild;
            let $chk = $B.DomUtils.children($wap, ".k_tree_check_box")[0];
            let $i = $chk.firstChild ? $chk.firstChild : $chk;
            let isChk;
            if (getNotEmpty) {
                isChk = !$B.DomUtils.hasClass($i, this.opts.chkEmptyIcon);
            } else {
                isChk = $B.DomUtils.hasClass($i, this.opts.chkAllIcon);
            }
            if (isChk) {
                let id = $B.DomUtils.attribute(li, "id").replace("_","");
                if (id !== "") {
                    if (typeof onlyId === "undefined" || onlyId) {
                        ret.push(id);
                    } else {
                        let $txt = $chk.nextSibling;
                        ret.push({ id: id, text: $txt.innerText });
                    }
                }
            }
        });
        return ret;
    }
    reload(ul, params) {
        if (!ul) {
            ul = this.elObj;
        } else if (!$B.isElement(ul)) {
            params = ul;
            ul = this.elObj;
        }
        if ($B.Dom.hasClass(ul, "k_tree_root")) {
            this.$firstEL = undefined;
        }
        let data, clickBtn;
        if (!$B.DomUtils.hasClass(ul, "k_tree_root")) {
            let $it = ul.previousSibling;
            data = this.getClickItemData($it);
            let firstEl = $it.firstChild;
            while (firstEl) {
                if ($B.DomUtils.hasClass(firstEl, "_node_") || $B.DomUtils.hasClass(firstEl, "_parent_")) {
                    break;
                }
                firstEl = firstEl.nextSibling;
            }
            clickBtn = firstEl;
        }
        $B.DomUtils.removeChilds(ul);
        setTimeout(() => {
            _load(this, ul, params, clickBtn, (retData) => {
                if (data) {
                    data.bean.children = retData;
                } else {
                    this.opts.data = retData;
                    this.triggerFirstClick();
                }
            });
        }, 1);
    }
    triggerFirstClick() {
        if (this.opts.clickFirst && this.$firstEL) {
            this.triggerClick(this.$firstEL);
        }
    }
    triggerClick($li) {
        this.itemEvent({ target: $li.firstChild });
    }
    updateNode() {
        let $it = this.clickedItem;
        let data;
        for (let i = 0; i < arguments.length; i++) {
            let arg = arguments[i];
            if ($B.Dom.isElement(arg)) {
                $it = arg;
            } else {
                data = arg;
            }
        }
        let uiId = "_" + data[this.opts.idField];
        if (!$it && data) {
            let $li = $B.Dom.findbyId(this.elObj, data[this.opts.idField]);
            if ($li) {
                $it = $li.firstChild;
            }
        } else if ($it.parentNode.id !== uiId) {
            $it = undefined;
            let $li = $B.Dom.findbyId(this.elObj, uiId);
            if ($li) {
                $it = $li.firstChild;
            }
        }
        if ($it) {
            let $txt = $B.Dom.children($it,".k_tree_text")[0];
            let bean = $B.DomUtils.getData($it, this.dataBeanKey);            
            let text = data[this.opts.textField];
            bean.text = text;
            $txt.innerText = text;
            $B.extendObjectFn( bean.data,data); 
        }
    }
    deleteNode(id){
        let $li = $B.Dom.findbyId(this.elObj, "_"+id);
        if($li){
            let ul = $li.parentNode;
            if($B.Dom.hasClass(ul,"k_tree_root")){
                this.opts.data = undefined;
                $B.Dom.removeChilds(ul);
            }else{
                let $prtEL = ul.previousSibling;
                let bean = $B.DomUtils.getData($prtEL, this.dataBeanKey); 
                let newChilds = [];
                let childs = bean.children;
                for(let i =0 ;i < childs.length ;i++){
                    if(childs[i].id !== id){
                        newChilds.push(childs[i]);
                    }
                }
                bean.children = newChilds;
                let $fchild = $li.firstChild ;
                let nextCall ;
                if($fchild === this.clickedItem){ //删除的刚好是激活行
                    nextCall = ()=>{
                        this.clickedItem = undefined;
                        this.itemEvent({target:$prtEL});
                    };                    
                }
                $B.Dom.remove($li);
                if(nextCall){
                    nextCall();
                }
            }
        }
    }
    /**
     * 可以是数据id，或者树节点元素div
     * **/
    reloadNode(args){
        let $node =  this.clickedItem;
        if(args){
            if($B.Dom.isElement(args)){
                $node = args;
            }else if(typeof args === "string"){
                let $li = $B.Dom.findbyId(this.elObj, "_"+args);
                if ($li) {
                    $node = $li.firstChild;
                }
            }
        }
        if($node){            
            let ul = $node.nextSibling;
            if(ul){
                let ret = this.getClickItemData($node);
                let clickBtn;
                let childs = $node.children;
                for(let i =0 ; i < childs.length ;i++){
                    if($B.Dom.attr(childs[i] , "event") === "parentEvent"){
                        clickBtn = childs[i];
                        break;
                    }
                }
                let deep = $B.Dom.attr( $node,"deep");   
                this.openDeep = deep + 1; 
                $B.DomUtils.removeChilds(ul);
                _load(this, ul, { pid: ret.bean.id }, clickBtn, (retData) => {
                    this.openDeep = undefined;
                    ret.bean.children = retData;
                });
            }            
        }
    }
    /**
     *  args = [id1,id2,id3];
     * ***/
    setValue(args) {
        if ($B.isPlainObjectFn(args)) {
            if (Array.isArray(args.id)) {
                args = args.id;
            }
        }
        var idMap = {};
        if (Array.isArray(args)) {
            for (let i = 0; i < args.length; i++) {
                idMap[args[i]] = true;
            }
        } else {
            idMap[args] = true;
        }
        let triggerEls = [];
        this.optimizeLoopTreeFn(this, this.elObj, (li) => {
            let $wap = li.firstChild;
            let id = $B.DomUtils.attribute(li, "id").replace("_","");
            if (this.opts.checkbox) {
                let $chk = $B.DomUtils.children($wap, ".k_tree_check_box")[0];
                $chk = $chk.firstChild ? $chk.firstChild : $chk;
                if ($B.DomUtils.hasClass($chk, this.opts.chkSomeIcon) || $B.DomUtils.hasClass($chk, this.opts.chkAllIcon)) {
                    let _data = $B.DomUtils.getData($wap, this.dataBeanKey);
                    _data.checked = false;
                    $B.DomUtils.removeClass($chk, this.opts.chkSomeIcon + " " + this.opts.chkAllIcon);
                    $B.DomUtils.addClass($chk, this.opts.chkEmptyIcon);
                }
            }
            if (idMap[id]) {
                if (this.opts.checkbox) {
                    let $chk = $B.DomUtils.children($wap, ".k_tree_check_box")[0];
                    if ($wap.nextSibling) {
                        if ($wap.nextSibling.children.length > 0) {
                            triggerEls.push($chk);
                        }
                    } else {
                        triggerEls.push($chk);
                    }
                } else {
                    if (idMap[id]) {
                        this.itemEvent({ target: $wap, _istrigger: true });
                        return true;
                    }
                }
            }
        });
        for (let i = 0; i < triggerEls.length; i++) {
            this.checkEvent({ target: triggerEls[i], _istrigger: true });
        }
    }
    _clear() {
        this.optimizeTree2ListFn("destroy");
        this.optimize2treeFn("destroy");
        this.optimizeCreateFn("destroy");
        this.optimizeLoopChildsFn("destroy");
        this.optimizeLoopParentsFn("destroy");
        this.optimizeLoopTreeFn("destroy");
    }
    destroy(isForce) {
        this._clear();
        super.destroy(isForce);
    }
    clear() {
        this._clear();
        super.clear();
    }
}
$B["Tree"] = Tree;